#include "h1010.h"
#include "SI.h"
#include "LED.h"
#include "SOSZ.h"
#include "Button.h"
#include "FWS.h"

#include <string.h>
#include <stdio.h>

struct FWS_threadInfo_t {
	uint8_t C1_local;
	uint8_t C2_local;
	uint16_t timer_local;
	uint16_t timer_abort;
	enum FWS_Sector mySector;
	enum FWS_State state;
	enum FWS_Status sectorStatus;
	enum FWS_Status inputStatus[FWS_INPUT_COUNT];
	enum FWS_InputCfgMask inputCfg[FWS_INPUT_COUNT];
	enum FWS_inputObjectType inputType[FWS_INPUT_COUNT];
	enum FWS_Status outputStatus[FWS_OUT_COUNT];
	bool_t hadFirstDumpOn;
	bool_t hadOneShotDump;
	enum FWS_Input lastInput;
	enum FWS_Input initiatingInput;
	struct FWS * pFWS;
	struct FWS_Ext02 * pFWS_Ext02;
};

struct FWS_outputTable_t {
	enum FWS_State state;
	enum FWS_Status hpSol;
	enum FWS_Status lpSol;
	enum FWS_Status preRelAnn;
	enum FWS_Status relAnn;
	enum FWS_Status shutdown;
	enum FWS_Status reset;
	enum FWS_Status relMode;
};

const struct FWS_outputTable_t FWS_outputTable [] = {
//			state							hpSol x		lpSol x		preRelAnn x		relAnnun x	shutdown		reset	x	relMode x
		{FWS_STATE_NULL, 				FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE},
		{FWS_STATE_STANDBY, 			FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE},

		{FWS_STATE_PRE_RELEASE, 		FWS_INACTIVE, FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_INACTIVE},

		{FWS_STATE_STARTUP, 			FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE},

		{FWS_STATE_FIRST_DUMP_ON, 		FWS_ACTIVE  , FWS_ACTIVE,   FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE},
		{FWS_STATE_DUMP_ON, 			FWS_ACTIVE,   FWS_ACTIVE,   FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE},
		{FWS_STATE_DUMP_OFF, 			FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE},

		{FWS_STATE_PAUSE, 				FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE},
		{FWS_STATE_RESET_ON, 			FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE,   FWS_ACTIVE},
		{FWS_STATE_RESET_OFF, 			FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_ACTIVE  , FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE},

		{FWS_STATE_ABORT, 				FWS_INACTIVE, FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_INACTIVE},
		{FWS_STATE_ABORT_WAIT_RELEASED, FWS_INACTIVE, FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_INACTIVE},
		{FWS_STATE_ABORT_TIMER, 		FWS_INACTIVE, FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_ACTIVE  , FWS_INACTIVE, FWS_INACTIVE},

		{FWS_STATE_NO_WATER, 			FWS_ACTIVE,   FWS_ACTIVE,   FWS_ACTIVE  , FWS_ACTIVE,   FWS_ACTIVE,   FWS_INACTIVE, FWS_INACTIVE},
		{FWS_STATE_WAIT_FOR_NEXT_ALARM, FWS_ACTIVE,   FWS_ACTIVE,   FWS_ACTIVE,   FWS_ACTIVE,   FWS_ACTIVE,   FWS_INACTIVE, FWS_INACTIVE},

		{FWS_STATE_CANCEL, 				FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE},
		{FWS_STATE_LOCKOFF, 			FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE, FWS_INACTIVE}
};

/* PRIVATE DATA */
struct FWS_threadInfo_t fwsThreadInfo[FWS_SECTOR_COUNT];
struct FWS_activeList_t {
	struct FWS_threadInfo_t * activeThread[FWS_SECTOR_COUNT];
	uint8_t count;
};
struct FWS_activeList_t FWS_activeList;
/* END PRIVATE DATA */

/* PRIVATE FUNCTION DECLARATIONS */
int FWS_updateInputs(enum FWS_Sector sector, enum FWS_Input begin, enum FWS_Input end);
void FWS_updateOutputs(struct FWS_threadInfo_t * me);
void FWS_walkAndDriveOutputs(struct FWS_threadInfo_t * me);
void FWS_resetOutputs(struct FWS_threadInfo_t * me);
enum FWS_OutputCfgMask FWS_getOutputCfg2(struct FWS_threadInfo_t * me, enum FWS_Output output);
enum SO_objectType FWS_getOutputCfgType(enum FWS_Sector sector, enum FWS_Output output);
enum SO_objectNumber FWS_getOutputCfgNum(enum FWS_Sector sector, enum FWS_Output output);
enum FWS_Status FWS_areInputsActive(struct FWS_threadInfo_t * me);
uint8_t FWS_activeList_walkListForSameHpActiveCount(struct FWS_threadInfo_t * me);
/* END PRIVATE FUNCTION DECLARATIONS */

enum FWS_Status FWS_isSectorActive(struct FWS_threadInfo_t * me)
{
	enum FWS_Status status = FWS_ACTIVE;
	if ((me->pFWS->input.Det1Input == 0) &&
		(me->pFWS->input.Det2Input == 0) &&
		(me->pFWS->input.MCPInput == 0))
	{
		status = FWS_INACTIVE;
	}
	else if ((me->pFWS->output.HPSolenoidOutput == 0) ||
			 (me->pFWS->output.LPSolenoidOutput == 0))
	{
		status = FWS_INACTIVE;
	}
	me->sectorStatus = status;
	return status;
}
void FWS_activeList_reset(struct FWS_activeList_t  * list)
{
	memset((void*)list, 0, sizeof(struct FWS_activeList_t));
}
void FWS_activeList_addSector(struct FWS_activeList_t * list, struct FWS_threadInfo_t * me)
{
	uint8_t count = list->count;
	if (count < FWS_SECTOR_COUNT)
	{
		list->activeThread[count] = me;
		list->count++;
	}
}
enum EventType {
	STATUS_EVENT,
	TIMER_EVENT,
	PB_EVENT
};
struct Event {
	enum EventType type;
	uint8_t id;
};
bool_t validDet1(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (me->inputStatus[FWS_INP_DET_ZONE_1] == FWS_ACTIVE)
		rtn = true;
	return rtn;
}
bool_t validDet2(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (me->inputStatus[FWS_INP_DET_ZONE_2] == FWS_ACTIVE)
		rtn = true;
	return rtn;
}
bool_t validMCPTrigger(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if(me->inputStatus[FWS_INP_MCP] == FWS_ACTIVE)
	{
		rtn = true;
	}
	return rtn;
}
bool_t validExtraRelTrigger(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if(me->pFWS->cfg.ReleaseAbort == FWS_extraRelease)
	{
		if(me->inputStatus[FWS_INP_EXTRA_RELEASE] == FWS_ACTIVE)
		{
			rtn = true;
		}
	}
	return rtn;
}
bool_t validDetCrossZone(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (validDet1(me) && validDet2(me))
		rtn = true;
	return rtn;
}
bool_t validDetNoCrossZone(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (validDet1(me) || validDet2(me))
		rtn = true;
	return rtn;
}
bool_t isCrossZoneSet(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (me->pFWS->cfg.XZone==1)
		rtn = true;
	return rtn;
}
bool_t isEnabledDet1PreRel(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (me->pFWS->cfg.EnableDet1PreReleaseDelay)
		rtn = true;
	return rtn;
}
bool_t isEnabledDet2PreRel(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (me->pFWS->cfg.EnableDet2PreReleaseDelay)
		rtn = true;
	return rtn;
}
bool_t checkCrossZone(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if(isCrossZoneSet(me) && validDetCrossZone(me))
	{
		rtn = true;
	}
	return rtn;
}
bool_t checkNoCrossZone(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if(!isCrossZoneSet(me) && validDetNoCrossZone(me))
	{
		rtn = true;
	}
	return rtn;
}
bool_t validDetectionTrigger(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if(checkCrossZone(me) || checkNoCrossZone(me))
	{
		rtn = true;
	}
	return rtn;
}
bool_t validPreReleaseDet1(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (isEnabledDet1PreRel(me) && validDet1(me))
	{
		rtn = true;
	}
	return rtn;
}
bool_t validPreReleaseDet2(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if (isEnabledDet2PreRel(me) && validDet2(me))
	{
		rtn = true;
	}
	return rtn;
}
bool_t validPreRelease(struct FWS_threadInfo_t * me)
{
	bool_t rtn = false;
	if ((isCrossZoneSet(me) && (isEnabledDet1PreRel(me) || isEnabledDet2PreRel(me))))
	{
		rtn = validDetectionTrigger(me);
	}
	else if (!isCrossZoneSet(me))
	{
		if (validPreReleaseDet1(me) || validPreReleaseDet2(me))
		{
			rtn = true;
		}
	}
	if (rtn == false && me->pFWS->cfg.EnableMCPPreReleaseDelay)
	{
		rtn = validMCPTrigger(me);
	}
	if (rtn == false && true==validExtraRelTrigger(me))
	{
		rtn = true;
	}
	return rtn;
}
void FWS_transToDumpOn_updateC1(struct FWS_threadInfo_t * me)
{
//	if (me->C1_local == 0)
	if (me->pFWS->timers.C1Counter == 0)
	{
		me->C1_local = 1;
	}
	else
	{
		me->C1_local = me->pFWS->timers.C1Counter;
	}
	me->state = FWS_STATE_DUMP_ON;
}
void FWS_checkTimers(struct FWS_threadInfo_t * me)
{
//	me->timer_local = 0;
	switch(me->state)
	{
		case FWS_STATE_STANDBY:
		case FWS_STATE_CANCEL:
		case FWS_STATE_LOCKOFF:
			if (validMCPTrigger(me))
			{
				me->initiatingInput = FWS_INP_MCP;
			}
			if ((me->pFWS->timers.PreReleaseTimer)&&(validPreRelease(me)))
			{
				me->state = FWS_STATE_PRE_RELEASE;
				break;
			}
		case FWS_STATE_PRE_RELEASE:
		case FWS_STATE_ABORT:
		case FWS_STATE_ABORT_WAIT_RELEASED:
		case FWS_STATE_ABORT_TIMER:
			me->C2_local = me->pFWS->timers.C2Counter;
			if (me->pFWS->timers.StartupTimer)
			{
				me->state = FWS_STATE_STARTUP;
				break;
			}
		case FWS_STATE_STARTUP:
		case FWS_STATE_WAIT_FOR_NEXT_ALARM:
			if (me->pFWS->timers.DumpOnTimer)
			{
				FWS_transToDumpOn_updateC1(me);
				if (me->hadFirstDumpOn==false && me->pFWS_Ext02->FirstDumpOnTimer)
				{
					me->hadFirstDumpOn = true;
					me->state = FWS_STATE_FIRST_DUMP_ON;
				}
				break;
			}
		default:
			me->state = FWS_STATE_NO_WATER;//FWS_STATE_WAIT_FOR_NEXT_ALARM;
			break;
		case FWS_STATE_NO_WATER:
		case FWS_STATE_FIRST_DUMP_ON:
		case FWS_STATE_DUMP_ON:
		case FWS_STATE_DUMP_OFF:
		case FWS_STATE_PAUSE:
		case FWS_STATE_RESET_ON:
		case FWS_STATE_RESET_OFF:
			// do nothing
			break;
	}
}
void FWS_endOfCycle(struct FWS_threadInfo_t * me)
{
//	me->timer_local = 0;
	/* decrement THEN check C2*/
	// decrement C2 if C2>0
	if (me->C2_local != 0) // don't decrement if C2=0
	{
		me->C2_local--; // decrement
	}
	// check C2
	if (me->C2_local != 0)
	{
//		me->C2_local--;
		if (FWS_areInputsActive(me) == FWS_ACTIVE)
		{	// inputs still active
			if (me->pFWS->timers.DumpOnTimer != 0)
			{
				FWS_transToDumpOn_updateC1(me);
				// Don't check for first dump on, because we would have already checked and been there
			}
			else
			{
//				me->state = ????;
				me->state = FWS_STATE_WAIT_FOR_NEXT_ALARM;
			}
		}
		else
		{	// inputs are normal
			me->state = FWS_STATE_WAIT_FOR_NEXT_ALARM;
		}
	}
	else  // c2 == 0
	{
		me->state = FWS_STATE_NO_WATER;
	}
}
void FWS_dumpCycle(struct FWS_threadInfo_t * me)
{
//	me->timer_local = 0;
	if (me->lastInput == FWS_INP_MCP)
	{
		if (me->pFWS->cfg.MCPOneShot)
		{
			me->hadOneShotDump = true;
		}
	}
	else if (me->lastInput == FWS_INP_DET_ZONE_1)
	{
		if (me->pFWS->cfg.Det1OneShot)
		{
			me->hadOneShotDump = true;
		}
	}
	/* decrement THEN check C1*/
	// decrement C1 if C1>0
	if (me->C1_local != 0) // don't decrement if C1=0
	{
		me->C1_local--; // decrement
	}
	// check C1
	if ((me->C1_local != 0) && (me->hadOneShotDump == false))
	{
//		me->C1_local--;
		if (me->pFWS->timers.DumpOffTimer != 0)
		{
			me->state = FWS_STATE_DUMP_OFF;
		}
		else // timer.dumpOff == 0
		{
			me->state = FWS_STATE_NO_WATER;
		}
	}
	else // c1 == 0 || hadOneShotDump = true
	{
		if (me->pFWS->timers.PauseTimer != 0)
		{
			me->state = FWS_STATE_PAUSE;
		}
		else if (me->pFWS->timers.ResetTimer)
		{
			me->state = FWS_STATE_RESET_ON;
		}
		else // timers.pause = 0 and timers.reset=0
		{
			FWS_endOfCycle(me);
		}
	}
}
int FWS_localTimerCheck(struct FWS_threadInfo_t * me, BYTE timerVal)
{
	if (++me->timer_local == timerVal)
	{
		me->timer_local = 0;
		return 1;
	}
	return 0;
}
uint8_t FWS_checkForValidAlarms(struct FWS_threadInfo_t * me)
{
	uint8_t rtn = 0;
	if ((validDetectionTrigger(me)) || (validMCPTrigger(me)) || (validExtraRelTrigger(me)))
	{
		if (FWS_activeList_walkListForSameHpActiveCount(me) < me->pFWS->timers.Interlock)
		{
			rtn = 1;
			FWS_checkTimers(me);
		}
	}
	return rtn;
}
void FWS_StateDuring_standby(struct FWS_threadInfo_t * me)
{
	me->initiatingInput = FWS_INP_BEGIN;
	if (FWS_checkForValidAlarms(me) == 1)
		__no_operation();
	else if (me->pFWS->cfg.LockoffCancel==FWS_lockoff && me->inputStatus[FWS_INP_LOCKOFF] == FWS_ACTIVE)
	{
		me->state = FWS_STATE_LOCKOFF;
	}
}
int FWS_mcpCheckDuringPreReleaseOrAbort(struct FWS_threadInfo_t * me)
{
	if (me->inputStatus[FWS_INP_MCP]==FWS_ACTIVE && me->initiatingInput!=FWS_INP_MCP /*&& me->lastInput==FWS_INP_MCP*/)
	{
		__no_operation();
		return 1;
	}
	return 0;
}
void FWS_StateDuring_preRelease(struct FWS_threadInfo_t * me)
{
//	if (++me->timer_local == me->pFWS->timers.PreReleaseTimer)
	if (FWS_localTimerCheck(me, me->pFWS->timers.PreReleaseTimer))
	{
//		if (FWS_areInputsActive(me) == FWS_ACTIVE)
			FWS_checkTimers(me);
//		else
	}
	else if (FWS_mcpCheckDuringPreReleaseOrAbort(me))
	{
		FWS_checkTimers(me);
	}
	else if (me->inputStatus[FWS_INP_ABORT]==FWS_ACTIVE) // && (me->pFWS->cfg.ReleaseAbort == FWS_abort)) // this check shouldn't be needed b/c it is handled where abort input is checked
	{
		me->state = FWS_STATE_ABORT;
		me->timer_abort = (me->pFWS->timers.PreReleaseTimer - me->timer_local); // time remaining in preRelease
		me->timer_abort += me->pFWS->timers.AbortTimer;
		me->timer_local = 0;
	}
}
void FWS_StateDuring_abort(struct FWS_threadInfo_t * me)
{
	// this state supposes that the Abort input is still pressed
//	if (++me->timer_local == me->timer_abort)
	if (FWS_localTimerCheck(me, me->timer_abort))
	{
		me->state = FWS_STATE_ABORT_WAIT_RELEASED;
	}
	else if (FWS_mcpCheckDuringPreReleaseOrAbort(me))
	{
		FWS_checkTimers(me);
	}
	else if (me->inputStatus[FWS_INP_ABORT] == FWS_INACTIVE)
	{
		me->state = FWS_STATE_ABORT_TIMER;
	}
}
void FWS_StateDuring_abortWaitReleased(struct FWS_threadInfo_t * me)
{
	// this state has the same behavior of abortTimer, except it doesn't increment the abortTimer because it has expired
	if (me->inputStatus[FWS_INP_ABORT] == FWS_INACTIVE)
	{
		if (FWS_areInputsActive(me) == FWS_ACTIVE)
		{
			FWS_checkTimers(me);
		}
		else
		{
			me->state = FWS_STATE_STANDBY;
		}
	}
	else if (FWS_mcpCheckDuringPreReleaseOrAbort(me))
	{
		FWS_checkTimers(me);
	}
}
void FWS_StateDuring_abortTimer(struct FWS_threadInfo_t * me)
{
	// the abort timer is still active, this state has a precondition that the abort input is no longer set
	// what if abort comes back???? I think the requirements say that abort can only be used once???
//	if (++me->timer_local == me->timer_abort)
	if (FWS_localTimerCheck(me, me->timer_abort))
	{
		if (FWS_areInputsActive(me) == FWS_ACTIVE)
		{
			FWS_checkTimers(me);
		}
		else
		{
			me->state = FWS_STATE_STANDBY;
		}
	}
	else if (FWS_mcpCheckDuringPreReleaseOrAbort(me))
	{
		FWS_checkTimers(me);
	}
}
void FWS_StateDuring_startup(struct FWS_threadInfo_t * me)
{
//	if (++me->timer_local == me->pFWS->timers.StartupTimer)
	if (FWS_localTimerCheck(me, me->pFWS->timers.StartupTimer))
	{
		FWS_checkTimers(me);
	}
}
void FWS_StateDuring_firstDumpOn(struct FWS_threadInfo_t * me)
{
//	if (++me->timer_local == me->pFWS_Ext02->FirstDumpOnTimer)
	if (FWS_localTimerCheck(me, me->pFWS_Ext02->FirstDumpOnTimer))
	{
		FWS_dumpCycle(me);
	}
}
void FWS_StateDuring_dumpOn(struct FWS_threadInfo_t * me)
{
//	if (++me->timer_local == me->pFWS->timers.DumpOnTimer)
	if (FWS_localTimerCheck(me, me->pFWS->timers.DumpOnTimer))
	{
		FWS_dumpCycle(me);
	}
}
void FWS_StateDuring_dumpOff(struct FWS_threadInfo_t * me)
{
//	if (++me->timer_local == me->pFWS->timers.DumpOffTimer)
	if (FWS_localTimerCheck(me, me->pFWS->timers.DumpOffTimer))
	{
//		me->timer_local = 0;
		// Don't need to validate dump on timer because we only enter dump off from dump on
		me->state = FWS_STATE_DUMP_ON;
	}
}
void FWS_StateDuring_pause(struct FWS_threadInfo_t * me)
{
	if (FWS_localTimerCheck(me, me->pFWS->timers.PauseTimer))
	{
//		me->timer_local = 0;
		if (me->pFWS->timers.ResetTimer)
		{
			me->state = FWS_STATE_RESET_ON;
		}
		else
		{
			FWS_endOfCycle(me);
		}
	}
}
void FWS_StateDuring_resetOn(struct FWS_threadInfo_t * me)
{
	if (FWS_localTimerCheck(me, me->pFWS->timers.ResetTimer))
	{
		me->state = FWS_STATE_RESET_OFF;
	}
}
void FWS_StateDuring_resetOff(struct FWS_threadInfo_t * me)
{
	if (FWS_localTimerCheck(me, me->pFWS->timers.ResetTimer))
	{
		FWS_endOfCycle(me);
	}
}
void FWS_StateDuring_noWater(struct FWS_threadInfo_t * me)
{
	if (evt_yes == BTN_btnEvent_get(eBtnReset))
	{
		BTN_btnEvent_consume(eBtnReset);
		if (!(validDetectionTrigger(me)) && !(validMCPTrigger(me)) && !(validExtraRelTrigger(me)))
		{
			me->state = FWS_STATE_STANDBY;
		}
	}
}
void FWS_StateDuring_waitForNextAlarm(struct FWS_threadInfo_t * me)
{
	/* Pre-condition for entering this state: no alarms present*/
	if (FWS_checkForValidAlarms(me) == 1)
			__no_operation();
	else if (evt_yes == BTN_btnEvent_get(eBtnReset))
	{
		BTN_btnEvent_consume(eBtnReset);
		if (!(validDetectionTrigger(me)) && !(validMCPTrigger(me)))
		{
			me->state = FWS_STATE_STANDBY;
		}
	}
}
void FWS_StateDuring_lockoff(struct FWS_threadInfo_t * me)
{
	if (me->inputStatus[FWS_INP_LOCKOFF]==FWS_INACTIVE)
	{
		if (!(validDetectionTrigger(me)) && !(validMCPTrigger(me)))
		{
			me->state = FWS_STATE_STANDBY;
		}
		else
		{
			FWS_checkTimers(me);
		}
	}
}
void FWS_StateDuring_cancel(struct FWS_threadInfo_t * me)
{
	if ((evt_yes == BTN_btnEvent_get(eBtnReset)) && (me->inputStatus[FWS_INP_CANCEL]==FWS_INACTIVE))
	{
		BTN_btnEvent_consume(eBtnReset);
		if (!(validDetectionTrigger(me)) && !(validMCPTrigger(me)))
		{
			me->state = FWS_STATE_STANDBY;
		}
	}
}
void FWS_processThread(struct FWS_threadInfo_t * me)//, struct Event * event)
{
	if(me->pFWS->cfg.LockoffCancel==FWS_cancel && me->inputStatus[FWS_INP_CANCEL]==FWS_ACTIVE)
	{
		FWS_resetOutputs(me);
		me->state = FWS_STATE_CANCEL;
	}
	switch(me->state)
	{
		case FWS_STATE_STANDBY:
			FWS_StateDuring_standby(me);
			break;
		case FWS_STATE_PRE_RELEASE:
			FWS_StateDuring_preRelease(me);
			break;
		case FWS_STATE_ABORT:
			FWS_StateDuring_abort(me);
			break;
		case FWS_STATE_ABORT_WAIT_RELEASED:
			FWS_StateDuring_abortWaitReleased(me);
			break;
		case FWS_STATE_ABORT_TIMER:
			FWS_StateDuring_abortTimer(me);
			break;
		case FWS_STATE_STARTUP:
			FWS_StateDuring_startup(me);
			break;
		case FWS_STATE_FIRST_DUMP_ON:
			FWS_StateDuring_firstDumpOn(me);
			break;
		case FWS_STATE_DUMP_ON:
			FWS_StateDuring_dumpOn(me);
			break;
		case FWS_STATE_DUMP_OFF:
			FWS_StateDuring_dumpOff(me);
			break;
		case FWS_STATE_PAUSE:
			FWS_StateDuring_pause(me);
			break;
		case FWS_STATE_RESET_ON:
			FWS_StateDuring_resetOn(me);
			break;
		case FWS_STATE_RESET_OFF:
			FWS_StateDuring_resetOff(me);
			break;
		case FWS_STATE_NO_WATER:
			FWS_StateDuring_noWater(me);
			break;
		case FWS_STATE_WAIT_FOR_NEXT_ALARM:
			FWS_StateDuring_waitForNextAlarm(me);
			break;
		case FWS_STATE_LOCKOFF:
			FWS_StateDuring_lockoff(me);
			break;
		case FWS_STATE_CANCEL:
			FWS_StateDuring_cancel(me);
			break;
	}
}
uint8_t FWS_activeList_walkListForSameHpActiveCount(struct FWS_threadInfo_t * me)
{
	struct FWS_activeList_t * list = &FWS_activeList;
	uint8_t i = 0;
	struct FWS_threadInfo_t * activeThread = 0;
	BYTE myHpSol = me->pFWS->output.HPSolenoidOutput;
	uint8_t almCnt = 0;
	while ((list->activeThread[i] !=0) && (i<=list->count) && (i<FWS_SECTOR_COUNT))
	{
		activeThread = list->activeThread[i];
		if (activeThread !=0)
		{
			if (myHpSol == activeThread->pFWS->output.HPSolenoidOutput)
			{
				if (activeThread->state > FWS_STATE_STANDBY)
				{
//					if ((me == activeThread) && (me->outputStatus[FWS_OUT_HP_SOL] == FWS_ACTIVE))
					if (me != activeThread)
					{
						almCnt++;
					}
				}
			}
		}
		i++;
	}
	return almCnt;
}
void FWS_spoolSectorOutputDrives(enum FWS_OutputCfgMask output, enum FWS_Status status);
void FWS_spoolSectorOutputDrivesReset(void);
void FWS_drivePhysicalOutputs(void);
void FWS_activeList_processList(struct FWS_activeList_t * list)
{
	uint8_t i = 0;
	struct FWS_threadInfo_t * activeThread = 0;
	FWS_spoolSectorOutputDrivesReset();
	while ((list->activeThread[i] !=0) && (i<=list->count) && (i<FWS_SECTOR_COUNT))
	{
		activeThread = list->activeThread[i];
		if (activeThread !=0)
		{
			FWS_updateInputs(activeThread->mySector, FWS_INP_BEGIN, FWS_INP_END);
			FWS_processThread(activeThread);
			FWS_updateOutputs(activeThread);
			FWS_walkAndDriveOutputs(activeThread);
		}
		i++;
	}
	FWS_drivePhysicalOutputs();
}
void FWS_threadInfo_zero(struct FWS_threadInfo_t * me)
{
	memset((void*)me, 0, sizeof(struct FWS_threadInfo_t));
}
void FWS_resetOutputs(struct FWS_threadInfo_t * me)
{
	memset((void*)me->outputStatus, FWS_INACTIVE, sizeof(me->outputStatus));
}
void FWS_resetInputs(struct FWS_threadInfo_t * me)
{
	memset((void*)me->inputStatus, FWS_INACTIVE, sizeof(me->inputStatus));
}
int FWS_threadInfo_initHelper(struct FWS_threadInfo_t * me, enum FWS_Sector fwsSector)//enum LED_INDEX alarm, enum LED_INDEX fault, enum LED_INDEX gblAlm)
{
	if (me == 0) return -1;
	FWS_threadInfo_zero(me);
	FWS_resetOutputs(me);
	FWS_resetInputs(me);
	me->lastInput = FWS_INPUT_COUNT;
	me->mySector = fwsSector;
	me->state = FWS_STATE_STANDBY;
	me->pFWS = (struct FWS *)&pConfigMemRAM->fws[fwsSector];
	me->pFWS_Ext02 = (struct FWS_Ext02 *)&pConfigMemRAM->fwsEx02[fwsSector];
	me->hadOneShotDump = false;
	if (me->pFWS->timers.Interlock == 0)
	{
		me->pFWS->timers.Interlock = 1;
	}
	me->C2_local = me->pFWS->timers.C2Counter;
	if (FWS_isSectorActive(me) != FWS_INACTIVE)
	{
		me->sectorStatus = FWS_ACTIVE;
		FWS_activeList_addSector(&FWS_activeList, me);
		enum FWS_Output i;
		enum FWS_OutputCfgMask cfg;
		enum SO_objectType objType;
		enum SO_objectNumber num;
		for (i=FWS_OUT_BEGIN; i<FWS_OUT_COUNT; i++)
		{
			cfg=FWS_getOutputCfg2(me, i);
			if(cfg)
			{
				objType = FWS_getOutputCfgType(fwsSector, i);
				num = FWS_getOutputCfgNum(fwsSector, i);
				SO_FWS_setSoMode(objType, num, SO_MODE_FWS);
			}
			// else -- do nothing
		}
	}
	else
	{
		me->sectorStatus = FWS_INACTIVE;
	}
	return 0;
}
void FWS_threadInfo_init(void)//enum LED_INDEX alarm, enum LED_INDEX fault, enum LED_INDEX gblAlm)
{
	enum FWS_Sector i;
	for(i=FWS_SECTOR_BEGIN; i<FWS_SECTOR_COUNT; i++)
	{
		FWS_threadInfo_initHelper(&fwsThreadInfo[i], i);
	}
}
void FWS_init(void)
{
	FWS_activeList_reset(&FWS_activeList);
	FWS_threadInfo_init();
}
void FWS_thread(void)
{
//	FWS_init();
//	while (1)
//	{
	FWS_activeList_processList(&FWS_activeList);
//	}
}
void FWS_endOfCycleProcessing(struct FWS_threadInfo_t * me);
void FWS_beginCycleProcessing(struct FWS_threadInfo_t * me);

enum SO_objectNumber FWS_convertFWSOutputToSoObject(enum FWS_OutputCfgMask targetOutput, enum SO_objectNumber begIndexSo, enum FWS_OutputCfgMask begIndexFws)
{
	enum SO_objectNumber objNum;
	enum SO_objectNumber offset = (enum SO_objectNumber)begIndexFws;
	offset -= begIndexSo;
	objNum = (enum SO_objectNumber)targetOutput;
	objNum -= offset;
	return objNum;
}
uint8_t fwsRelayRequest [4];
uint8_t fwsSupOutRequest [4];
void FWS_spoolSectorOutputDrivesReset(void)
{
	memset(&fwsRelayRequest, 0, sizeof(fwsRelayRequest));
	memset(&fwsSupOutRequest, 0, sizeof(fwsSupOutRequest));
}
void FWS_spoolSectorOutputDrives(enum FWS_OutputCfgMask output, enum FWS_Status status)
{
	enum SO_objectNumber id;
	switch (output)
	{
		case FWS_OUT_CFG_SO_1:
		case FWS_OUT_CFG_SO_2:
		case FWS_OUT_CFG_SO_3:
		case FWS_OUT_CFG_SO_4:
			id = FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_SO_1);
			if (status == FWS_ACTIVE)
				fwsSupOutRequest[id]=FWS_ACTIVE;
/*			else
			{
				if (fwsSupOutRequest[id]==FWS_ACTIVE){
					__no_operation(); // do nothing
				}
				else
				{
					fwsSupOutRequest[id]=FWS_INACTIVE;
				}
			}*/
		break;
		case FWS_OUT_CFG_RL_1:
		case FWS_OUT_CFG_RL_2:
		case FWS_OUT_CFG_RL_3:
		case FWS_OUT_CFG_RL_4:
			id = FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_RL_1);
			if (status == FWS_ACTIVE)
				fwsRelayRequest[id]=FWS_ACTIVE;
//				SO_FWS_notifyOutputSpool(SO_T_RL, FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_RL_1));
//			else
//				SO_FWS_clearOutputSpool(SO_T_RL, FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_RL_1));
		break;
	}
}
void FWS_drivePhysicalOutputs(void)
{
	enum SO_objectNumber i;
	for (i=SO_OBJ_1; i<SO_OBJ_5; i++)
	{
		if (fwsSupOutRequest[i]==FWS_ACTIVE)
		{
			SO_FWS_notifyOutput(SO_T_SO, i);
		}
		else
		{
			SO_FWS_clearOutput(SO_T_SO, i);
		}
		if (fwsRelayRequest[i]==FWS_ACTIVE)
		{
			SO_FWS_notifyOutput(SO_T_RL, i);
		}
		else
		{
			SO_FWS_clearOutput(SO_T_RL, i);
		}
	}
}
void FWS_driveOutput(enum FWS_OutputCfgMask output, enum FWS_Status status)
{
	switch (output)
	{
		case FWS_OUT_CFG_SO_1:
		case FWS_OUT_CFG_SO_2:
		case FWS_OUT_CFG_SO_3:
		case FWS_OUT_CFG_SO_4:
			if (status == FWS_ACTIVE)
				SO_FWS_notifyOutput(SO_T_SO, FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_SO_1));
			else
				SO_FWS_clearOutput(SO_T_SO, FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_SO_1));
		break;
		case FWS_OUT_CFG_RL_1:
		case FWS_OUT_CFG_RL_2:
		case FWS_OUT_CFG_RL_3:
		case FWS_OUT_CFG_RL_4:
			if (status == FWS_ACTIVE)
				SO_FWS_notifyOutput(SO_T_RL, FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_RL_1));
			else
				SO_FWS_clearOutput(SO_T_RL, FWS_convertFWSOutputToSoObject(output, SO_OBJ_1, FWS_OUT_CFG_RL_1));
		break;
	}
}
enum FWS_OutputCfgMask FWS_getOutputCfg22(enum FWS_Sector sector, enum FWS_Output output)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	return (enum FWS_OutputCfgMask)FWS_getOutputCfg2(me, output);
}
enum FWS_OutputCfgMask FWS_getOutputCfg2(struct FWS_threadInfo_t * me, enum FWS_Output output)
{
	enum FWS_OutputCfgMask cfg;
	uint8_t * pCfg = 0;
	if (output != FWS_OUT_RELEASE_MODE)
	{
		pCfg = (uint8_t*)&me->pFWS->output;
		cfg = (enum FWS_OutputCfgMask)pCfg[output];
	}
	else
	{
		pCfg = (uint8_t*)&me->pFWS_Ext02->ReleaseModeOutput;
		cfg = (enum FWS_OutputCfgMask)*pCfg;
	}
	return cfg;
}
void FWS_walkAndDriveOutputs(struct FWS_threadInfo_t * me)
{
	enum FWS_Output i;
	enum FWS_OutputCfgMask cfg;
	for (i=FWS_OUT_BEGIN; i<FWS_OUT_COUNT; i++)
	{
		if(cfg=FWS_getOutputCfg2(me, i)) // if output is configured
		{
			FWS_spoolSectorOutputDrives(cfg, me->outputStatus[i]);
//			FWS_driveOutput(cfg, me->outputStatus[i]);
		}
		// else -- do nothing
	}
}
void FWS_updateOutputs(struct FWS_threadInfo_t * me)
{
	me->outputStatus[FWS_OUT_HP_SOL] 		= FWS_outputTable[me->state].hpSol;
	me->outputStatus[FWS_OUT_LP_SOL] 		= FWS_outputTable[me->state].lpSol;
	me->outputStatus[FWS_OUT_PRE_REL_ANNUN] = FWS_outputTable[me->state].preRelAnn;
	me->outputStatus[FWS_OUT_REL_ANNUN] 	= FWS_outputTable[me->state].relAnn;
	me->outputStatus[FWS_OUT_SHUTDOWN] 		= FWS_outputTable[me->state].shutdown;
	me->outputStatus[FWS_OUT_RESET] 		= FWS_outputTable[me->state].reset;
	if (me->pFWS_Ext02->ReleaseModeOutput)
		me->outputStatus[FWS_OUT_RELEASE_MODE] 	= FWS_outputTable[me->state].relMode;
	else
		me->outputStatus[FWS_OUT_RELEASE_MODE] 	= FWS_INACTIVE;
}
enum FWS_Status FWS_getOutputStatus(enum FWS_Sector sector, enum FWS_Output output)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_Status status = me->outputStatus[output];//FWS_STATUS_NULL;
	return status;
}
void FWS_setOutputStatus(enum FWS_Sector sector, enum FWS_Output output, enum FWS_Status status)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	switch (output)
	{
		case FWS_OUT_HP_SOL:
			if (me->pFWS->output.HPSolenoidOutput != 0)
			{
				me->outputStatus[FWS_OUT_HP_SOL] = status;
				FWS_driveOutput((enum FWS_OutputCfgMask)me->pFWS->output.HPSolenoidOutput, status);
			}
			break;
		case FWS_OUT_LP_SOL:
			if (me->pFWS->output.LPSolenoidOutput != 0)
			{
				me->outputStatus[FWS_OUT_LP_SOL] = status;
			}
			break;
		case FWS_OUT_PRE_REL_ANNUN:
			if (me->pFWS->output.PreReleaseAnnOutput != 0)
			{
				me->outputStatus[FWS_OUT_PRE_REL_ANNUN] = status;
			}
			break;
		case FWS_OUT_REL_ANNUN:
			if (me->pFWS->output.ReleaseAnnOutput != 0)
			{
				me->outputStatus[FWS_OUT_REL_ANNUN] = status;
			}
			break;
		case FWS_OUT_SHUTDOWN:
			if (me->pFWS->output.ShutdownOutput != 0)
			{
				me->outputStatus[FWS_OUT_SHUTDOWN] = status;
			}
			break;
		case FWS_OUT_RESET:
			if (me->pFWS->output.ResetOutput != 0)
			{
				me->outputStatus[FWS_OUT_RESET] = status;
			}
			break;
		case FWS_OUT_RELEASE_MODE:
			if (me->pFWS_Ext02->ReleaseModeOutput != 0)
			{
				me->outputStatus[FWS_OUT_RELEASE_MODE] = status;
			}
			break;
	}
}
enum FWS_OutputCfgMask FWS_getOutputCfg(enum FWS_Sector sector, enum FWS_Output output)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	if (me == 0) return FWS_OUT_CFG_NONE;
	uint8_t *pOut = (uint8_t*)&me->pFWS->output;
	enum FWS_OutputCfgMask cfg = (enum FWS_OutputCfgMask)pOut[output];
	return cfg;
}
enum SO_objectType FWS_getOutputCfgType(enum FWS_Sector sector, enum FWS_Output output)
{
	enum FWS_OutputCfgMask cfg = FWS_getOutputCfg22(sector, output);
	enum SO_objectType objType = SO_T_NULL;
	switch (cfg)
	{
		case FWS_OUT_CFG_SO_1:
		case FWS_OUT_CFG_SO_2:
		case FWS_OUT_CFG_SO_3:
		case FWS_OUT_CFG_SO_4:
			objType = SO_T_SO;
		break;
		case FWS_OUT_CFG_RL_1:
		case FWS_OUT_CFG_RL_2:
		case FWS_OUT_CFG_RL_3:
		case FWS_OUT_CFG_RL_4:
			objType = SO_T_RL;
		break;
	}
	return objType;
}
void FWS_getOutputCfgAll(enum FWS_Sector sector, enum FWS_Output output, enum FWS_OutputCfgMask *pcfg, enum SO_objectType *pobjType, enum SO_objectNumber *pnum)
{
	enum FWS_OutputCfgMask cfg = FWS_getOutputCfg22(sector, output);
	enum SO_objectType objType = SO_T_NULL;
	enum SO_objectNumber num 	= SO_OBJ_NULL;
	switch (cfg)
	{
		case FWS_OUT_CFG_SO_1:
		case FWS_OUT_CFG_SO_2:
		case FWS_OUT_CFG_SO_3:
		case FWS_OUT_CFG_SO_4:
			objType = SO_T_SO;
			num = FWS_convertFWSOutputToSoObject(cfg, SO_OBJ_1, FWS_OUT_CFG_SO_1);
		break;
		case FWS_OUT_CFG_RL_1:
		case FWS_OUT_CFG_RL_2:
		case FWS_OUT_CFG_RL_3:
		case FWS_OUT_CFG_RL_4:
			objType = SO_T_RL;
			num = FWS_convertFWSOutputToSoObject(cfg, SO_OBJ_1, FWS_OUT_CFG_RL_1);
		break;
	}
	*pcfg = cfg;
	*pobjType = objType;
	*pnum = num;
}
enum SO_objectNumber FWS_getOutputCfgNum(enum FWS_Sector sector, enum FWS_Output output)
{
	enum FWS_OutputCfgMask 	cfg 	= FWS_getOutputCfg22(sector, output);
	enum SO_objectType 		objType = FWS_getOutputCfgType(sector, output);
	enum SO_objectNumber 	num 	= SO_OBJ_NULL;

	switch (objType)
	{
	case SO_T_SO:
		num = FWS_convertFWSOutputToSoObject(cfg, SO_OBJ_1, FWS_OUT_CFG_SO_1);
		break;
	case SO_T_RL:
		num = FWS_convertFWSOutputToSoObject(cfg, SO_OBJ_1, FWS_OUT_CFG_RL_1);
		break;
	}
	return num;
}
void FWS_setOutputCfg(enum FWS_Sector sector, enum FWS_Output output, enum FWS_OutputCfgMask cfg)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	if (me == 0) return;
	uint8_t *pOut = (uint8_t*)&me->pFWS->output;
	pOut[(uint8_t)output] = (uint8_t)cfg;
}
enum FWS_Status FWS_getInputStatus(enum FWS_Sector sector, enum FWS_Input input)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_Status status = me->inputStatus[input];//FWS_STATUS_NULL;
	return status;
}
enum FWS_Status FWS_getInputStatus2(struct FWS_threadInfo_t * me, enum FWS_InputCfgMask inputCfg)
{
	enum objectStatus status;
	enum objectNumber num;
	enum FWS_Status rtn = FWS_INACTIVE;

	if (me == 0) return FWS_INACTIVE;

	if (inputCfg >= FWS_INP_CFG_SI_1 && inputCfg <= FWS_INP_CFG_SI_8)
	{
		num = (enum objectNumber)(inputCfg - FWS_INP_CFG_SI_1);
		status = SO_objStatus(OBJ_T_SI, num);
	}
	else if (inputCfg >= FWS_INP_CFG_SI_9 && inputCfg <= FWS_INP_CFG_SI_12)
	{
		num = (enum objectNumber)(inputCfg - 9);
		status = SO_objStatus(OBJ_T_SI, num);
	}
	else if (inputCfg >= FWS_INP_CFG_SZ_1 && inputCfg <= FWS_INP_CFG_SZ_8)
	{
		num = (enum objectNumber)(inputCfg - FWS_INP_CFG_SZ_1);
		status = SO_objStatus(OBJ_T_SZ, num);
	}
	else if (inputCfg >= FWS_INP_CFG_SZ_9 && inputCfg <= FWS_INP_CFG_SZ_12)
	{
		num = (enum objectNumber)(inputCfg - FWS_INP_CFG_SZ_1);
		status = SO_objStatus(OBJ_T_SZ, num);
	}
	if (status == OBJ_S_ACTIVE)
	{
		rtn = FWS_ACTIVE;
	}
	return rtn;
}
enum FWS_Status FWS_getInputPhyStatus(enum FWS_Sector sector, enum FWS_Input input)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_InputCfgMask cfg = FWS_getInputPhyCfg(sector, input);
	enum FWS_Status status = FWS_getInputStatus2(me, cfg);//FWS_STATUS_NULL;
	return status;
}
void FWS_enforceCfgLockoffCancel(struct FWS_threadInfo_t * me)
{
	if (me->pFWS->cfg.LockoffCancel == FWS_cancel) {
		me->inputStatus[FWS_INP_LOCKOFF] = FWS_INACTIVE;
	}
	else {
		me->inputStatus[FWS_INP_CANCEL] = FWS_INACTIVE;
	}
}
void FWS_enforceCfgAbortExtraRelease(struct FWS_threadInfo_t * me)
{
	if (me->pFWS->cfg.ReleaseAbort == FWS_extraRelease) {
		me->inputStatus[FWS_INP_ABORT] = FWS_INACTIVE;
	}
	else {
		me->inputStatus[FWS_INP_EXTRA_RELEASE] = FWS_INACTIVE;
	}
}
void FWS_enforceCfgInputSharedCfgByte(struct FWS_threadInfo_t * me)
{
	FWS_enforceCfgLockoffCancel(me);
	FWS_enforceCfgAbortExtraRelease(me);
}
enum FWS_Status FWS_areInputsActive(struct FWS_threadInfo_t * me)
{
	enum FWS_Status normal = FWS_INACTIVE;
	if ((me->inputStatus[FWS_INP_DET_ZONE_1] == FWS_ACTIVE)
	 || (me->inputStatus[FWS_INP_DET_ZONE_2] == FWS_ACTIVE)
	 || (me->inputStatus[FWS_INP_MCP] == FWS_ACTIVE)
	 || (me->inputStatus[FWS_INP_EXTRA_RELEASE] == FWS_ACTIVE))
	{
		normal = FWS_ACTIVE;
	}
	return normal;
}
int FWS_updateInputs(enum FWS_Sector sector, enum FWS_Input begin, enum FWS_Input end)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_Input i;
	enum FWS_Status temp;
	if (begin > end) return -1;
	for (i=begin; i<=end; i++)
	{
		temp = me->inputStatus[i];
		me->inputStatus[i] = FWS_getInputPhyStatus(sector, i);
//		if (i = FWS_INP_DET_ZONE_1 || i = FWS_INP_MCP)
//		{
			if (me->inputStatus[i] == FWS_ACTIVE)
			{
				if (temp != me->inputStatus[i])
				{
					me->lastInput = i;
				}
			}
//		}
	}
	FWS_enforceCfgInputSharedCfgByte(me);
	return 0;
}
enum SI_ADC_STATE FWS_getInputPhyAdcStatus(enum FWS_Sector sector, enum FWS_Input input)
{
	enum SI_ADC_STATE status = SI_ADC_NULL;
	switch (input)
	{
	case FWS_INP_DET_ZONE_1:
		break;
	case FWS_INP_DET_ZONE_2:
		break;
	case FWS_INP_MCP:
		break;
	case FWS_INP_LOCKOFF:
		break;
	case FWS_INP_CANCEL:
		break;
	case FWS_INP_ABORT:
		break;
	case FWS_INP_EXTRA_RELEASE:
		break;
	}
	return status;
}
enum FWS_InputCfgMask FWS_getInputPhyCfg(enum FWS_Sector sector, enum FWS_Input input)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	if (me == 0) return FWS_INP_CFG_NONE;
	uint8_t *pIn = 0;
	enum FWS_InputCfgMask cfg;
	switch (input)
	{
		case FWS_INP_LOCKOFF:
		case FWS_INP_CANCEL:
			cfg = (enum FWS_InputCfgMask)me->pFWS->input.LockoffInput;
			break;
		case FWS_INP_ABORT:
		case FWS_INP_EXTRA_RELEASE:
			cfg = (enum FWS_InputCfgMask)me->pFWS->input.AbortInput;
			break;
		default:
			pIn = (uint8_t*)&me->pFWS->input;
			cfg = (enum FWS_InputCfgMask)pIn[input];
//			cfg = (enum FWS_InputCfgMask)me->pFWS->input[input];
			break;
	}
	return cfg;
}
enum FWS_inputObjectType FWS_getInputPhyCfgType(enum FWS_Sector sector, enum FWS_Input input)
{
//	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_InputCfgMask cfg = FWS_getInputPhyCfg(sector, input);
	enum FWS_inputObjectType objType = FWS_T_NULL;
	switch (cfg)
	{
		case FWS_INP_CFG_SI_1:
		case FWS_INP_CFG_SI_2:
		case FWS_INP_CFG_SI_3:
		case FWS_INP_CFG_SI_4:
		case FWS_INP_CFG_SI_5:
		case FWS_INP_CFG_SI_6:
		case FWS_INP_CFG_SI_7:
		case FWS_INP_CFG_SI_8:
		case FWS_INP_CFG_SI_9:
		case FWS_INP_CFG_SI_10:
		case FWS_INP_CFG_SI_11:
		case FWS_INP_CFG_SI_12:
			objType = FWS_T_SI;
			break;
		case FWS_INP_CFG_SZ_1:
		case FWS_INP_CFG_SZ_2:
		case FWS_INP_CFG_SZ_3:
		case FWS_INP_CFG_SZ_4:
		case FWS_INP_CFG_SZ_5:
		case FWS_INP_CFG_SZ_6:
		case FWS_INP_CFG_SZ_7:
		case FWS_INP_CFG_SZ_8:
		case FWS_INP_CFG_SZ_9:
		case FWS_INP_CFG_SZ_10:
		case FWS_INP_CFG_SZ_11:
		case FWS_INP_CFG_SZ_12:
			objType = FWS_T_SZ;
			break;
	}
	return objType;
}

enum SI_X FWS_getInputPhyCfgNum(enum FWS_Sector sector, enum FWS_Input input)
{
//	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_inputObjectType objType = FWS_getInputPhyCfgType(sector, input);
	enum FWS_InputCfgMask cfg = FWS_getInputPhyCfg(sector, input);
	enum SI_X num = SI_NULL;
	switch (objType)
	{
		case FWS_T_SI:
			num = (enum SI_X)(cfg-1);
			break;
		case FWS_T_SZ:
			num = (enum SI_X)(cfg - FWS_INP_CFG_SZ_1 -1);
			break;
	}

	return num;
}
void FWS_setInputPhyCfg(enum FWS_Sector sector, enum FWS_Input input, enum FWS_InputCfgMask cfg)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	if (me == 0) return;
	uint8_t *pOut = (uint8_t*)&me->pFWS->input;
	pOut[(uint8_t)input] = (uint8_t)cfg;
}
void FWS_setInput(enum FWS_Sector sector, enum FWS_Input input, enum FWS_Status status)//enum SI_ADC_STATE value)
{
//	struct FWS_threadInfo_t * me = FWS_activeList.activeThread[sector];
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	switch (input)
	{
		case FWS_INP_DET_ZONE_1:
			if (me->pFWS->input.Det1Input != 0)
			{
				me->inputStatus[FWS_INP_DET_ZONE_1] = status;
			}
			break;
		case FWS_INP_DET_ZONE_2:
			if (me->pFWS->input.Det2Input != 0)
			{
				me->inputStatus[FWS_INP_DET_ZONE_2] = status;
			}
			break;
		case FWS_INP_MCP:
			if (me->pFWS->input.MCPInput != 0)
			{
				me->inputStatus[FWS_INP_MCP] = status;
			}
			break;
		case FWS_INP_LOCKOFF:
		case FWS_INP_CANCEL:
			if (me->pFWS->input.LockoffInput != 0)
			{
				if (me->pFWS->cfg.LockoffCancel == 1)//FWS_CFG_INPUT_CANCEL_1_LOCKOFF_0
				{
					// cancel
					me->inputStatus[FWS_INP_LOCKOFF] = FWS_INACTIVE;
					me->inputStatus[FWS_INP_CANCEL] = status;
				}
				else
				{
					// lockoff
					me->inputStatus[FWS_INP_LOCKOFF] = status;
					me->inputStatus[FWS_INP_CANCEL] = FWS_INACTIVE;
				}
			}
			break;
		case FWS_INP_ABORT:
		case FWS_INP_EXTRA_RELEASE:
			if (me->pFWS->input.AbortInput != 0)
			{
				if (me->pFWS->cfg.ReleaseAbort == 1)//FWS_CFG_INPUT_EXTRA_RELEASE_1_ABORT_0)
				{
					// extra release mode
					me->inputStatus[FWS_INP_ABORT] = FWS_INACTIVE;
					me->inputStatus[FWS_INP_EXTRA_RELEASE] = status;
				}
				else
				{
					// abort mode
					me->inputStatus[FWS_INP_ABORT] = status;
					me->inputStatus[FWS_INP_EXTRA_RELEASE] = FWS_INACTIVE;
				}
			}
			break;
	}
//	me->pFWS->input.Det1Input;
}
enum FWS_State FWS_getSectorState(enum FWS_Sector sector)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_State state = me->state;//FWS_STATE_NULL;
	return state;
}
enum FWS_Status FWS_getSectorStatus(enum FWS_Sector sector)
{
	struct FWS_threadInfo_t * me = &fwsThreadInfo[sector];
	enum FWS_Status status = me->sectorStatus;//FWS_STATUS_NULL;
	return status;
}
